National NPI* policies against the spread of COVID-19

*non-pharmaceutical-intervention

Author 1, affiliation
Author 2, affiliation
Author 3, affiliation
contact information

30/03/2020, Rome (Italy)

In [4]:
import pandas as pd
from lifelines import CoxTimeVaryingFitter
import datetime
import matplotlib.pyplot as plt
import seaborn as sns;sns.set()
import geopandas as gpd
import shapely.wkt
import os
import folium
from shapely import wkt
import branca.colormap as cm
from branca.element import Template, MacroElement
from matplotlib.patches import Rectangle
from matplotlib.dates import date2num
from folium import plugins
import jinja2
from shapely.ops import cascaded_union

By the time we are writing the recent global virus called COVID-19 has hit more than 190 countries and governments all over the globe have adopted (or are about to adopt) with different timing containment measures in order to limit the devastating effects it is causing to the economy and to people’s health. The disease has already reached a pandemic scale but still many governments hesitate taking action despite it is now clear to all that early or preventive measures can effectively limit the exponential spread.
Policy interventions include a variety of instruments and most of them imply citizens’ liberties restrictions and this appears to be one of the main drivers refraining governments from intervening. Moreover, besides social and political implications, those tools have also different relative costs and they could be not available for some countries.
A preventive intervention is key when dealing with these kind of diseases because it mainly allows to flatten the epidemiological curve in order to reduce the infection rate (and consequently losses in human lives) and also manage better the emergency preventing the healthcare systems from overload. The timing of this anticipated intervention is crucial for obtaining better results, as the example figure below shows, anticipation of the policy might obtain greater results in terms of reducing the overall losses created by the exponential spread of the epidemic (see red and green line).

Our monitoring project keeps daily track of the main adopted restrictions in order to monitor and evaluate the national responses, both in terms of which policies have been adopted as well as their timing in each country and have a clear view on the global state of the fight against Corona Virus. For this purpose, we built a dataset for monitoring policies that Governments have taken as countermeasures to tackle the spread of COVID-19. At the moment we are monitoring over 41 countries over different policies, from Lockdown, to closure of schools and cancellation of large events (for a detailed list of all variables we monitor see the information page of the dataset. We cross those data together with epidemic data from the Johns Hopkins Coronavirus Resource Center (JHCRC), as well with economic, political and demographic features of the countries under analysis.Our research objective is to understand why some governments are acting with delays, and what are the effects of this policies on the epidemic curve.

Below we give a brief of the data collected so far, for popular purpose. We will follow with the publication of a series of research material focused on specific related topics.

COVERAGE OF THE DATASET

At the moment we cover 38 countries, the selection has been made based on most developed countries and most hit as of the end of March 2020. This list of countries include all 35 OECD countries. In the map the yellow-coloured countries are those under analysis, in addition the violet-coloured countries are those for which we have data on virus spread from the JHCRC.

In [5]:
folder="D:\\database_vari_miei\\covid_database\\"
In [7]:
DATASET=pd.read_excel("POLITICAL_COVID_29_03_2020.xlsx",sheet_name="DATA")
### select only useful
DATASET=DATASET.iloc[0:DATASET["ISO3"].last_valid_index()+1,:]
DATASET_COMPLETE=pd.read_csv(folder+os.listdir(folder)[-1],index_col=0)
# ## list of country for which we have political data
country_analized=DATASET['ISO3'].unique()
policy_var=DATASET.columns
In [4]:
fig,axs=plt.subplots(figsize=(15,10))
mappa_mondo=gpd.read_file("C:\\Users\\gabri\\Desktop\\COVID\\limiti_mondo")
GPD_PLOT=gpd.GeoDataFrame(DATASET_COMPLETE.groupby('ISO3',as_index=False)['geometry'].first())
GPD_PLOT['in_dataset']="covid dataset"
GPD_PLOT['geometry']=GPD_PLOT['geometry'].apply(lambda x:shapely.wkt.loads(x))


GPD_PLOT.set_geometry('geometry',inplace=True)
GPD_PLOT.loc[GPD_PLOT['ISO3'].isin(DATASET['ISO3'].unique()),'in_dataset']="policy dataset"
##sfondo
mappa_mondo.plot(color='lightgrey',ax=axs)
GPD_PLOT.plot('in_dataset',ax=axs,cmap="viridis",legend=True)
axs.set_title('Dataset coverage update at '+datetime.datetime.today().strftime("%d/%m/%Y"));
axs.set_axis_off()

How countries are coordinating in the adoption of policies

The graph below, along time, how countries are adopting measures in response to a spike in the number of registered cases. As we can see, the week between the 16th and the 23rd of March has been of fundamental importance, with more than 20 countries deciding to close their schools, and 15 countries adopting "lockdown" policies. This graph suggests countries are choosing coordinately on their policies by looking at "what the others do". A visual interpretation of the graph suggests countries are following the spread of the virus when choosing their timing of adoption, instead of anticipating it. While the other MAPS below show countries’ adoption over different policies (school closing, lockdown, digital tracking and suspension of elections).

In [6]:
# selezionare solo i paesi censiti  
fig,axs=plt.subplots(figsize=(14,8))
DF=DATASET_COMPLETE.loc[DATASET_COMPLETE['ISO3'].isin(country_analized),:].copy()


policies=["LOCKDOWN_dummy","LOCKDOWN_LOCAL_dummy","SCHOOL_CLOSING_dummy","EVENT_LARGE_dummy"]
polic=["lockdown",'local lockdown','school closure','closure of large events']
diz_rename={}
for x,y in zip(policies,polic):
    diz_rename[x]="n. of countries adopting "+y

numero_policy_adopter=DF.groupby(['time'],as_index=False)["LOCKDOWN_dummy","LOCKDOWN_LOCAL_dummy","SCHOOL_CLOSING_dummy","EVENT_LARGE_dummy"].sum()
numero_casi=DF.groupby(['time'],as_index=False)['confirmed_cases'].sum()
DF_PLOT=pd.merge(numero_policy_adopter,numero_casi,on='time')
# nuovo_nome="Number of countries that have closed Schools (right axis)"
DF_PLOT.rename(diz_rename,axis=1,inplace=True)

DF_PLOT.set_index(pd.to_datetime(DF_PLOT['time']),inplace=True)
DF_PLOT.sort_index(inplace=True)

DF_PLOT.loc[:,diz_rename.values()].plot(ax=axs);
plt.legend(loc='upper left',fontsize=13);
axs2 = axs.twinx() 

DF_PLOT.loc[:,['confirmed_cases']].plot(ax=axs2,linestyle="dashed",color='black',linewidth=3)
plt.legend(loc='upper center',fontsize=13,labels=["total confirmed COVID-19 cases (right axis)"]);


plt.tight_layout()

Interactive maps

The next maps shows for some selected policies of our dataset, which countries are adopter. By dragging the mouse on a certain countries you can see also how many confirmed and deaths cases the country has.

In [7]:
var_policy=DATASET_COMPLETE.columns[DATASET_COMPLETE.columns.str.contains("_dummy")]
lista_var=['ISO3']
lista_var.extend(var_policy)

## only one day
world=gpd.GeoDataFrame(DATASET_COMPLETE.loc[DATASET_COMPLETE['time']==DATASET_COMPLETE['time'].max(),:])
## aggiustare coordinaate settings
world.crs='EPSG:4326'
world['geometry'] = world['geometry'].apply(wkt.loads)
world.set_geometry('geometry',inplace=True)
### bisogna prima trasformarlo in json
worldjson=world.to_json()

Confirmed COVID-19 cases as percentage of total population

In [20]:
m = folium.Map(location=[41.8, +12.5], zoom_start=2, tiles="cartodbpositron")
m.choropleth(worldjson, name="school_closing_layer",data=world, key_on='feature.properties.ISO3',
             columns=["ISO3","confirmed_cases"], fill_color='BuPu',legend_name="Total Confirmed Cases")
m
Out[20]:
In [34]:
### per ora non si può fare...le chart si possono fare solo con i marker
import altair as alt
df_figura=DF.loc[DF['ISO3']=="ITA",['confirmed_cases','time']]
json_figura=alt.Chart(df_figura).mark_line().encode(
    x='time:T',
    y='confirmed_cases:Q'
).to_json()
## this is the json object that should be passed to the popup
chart=folium.Vega(json_figura, width=450, height=250)
In [56]:
def map_plotter(nome_variabile,colore_si='green',colore_no='violet'):
    m = folium.Map(location=[41.8, +12.5], zoom_start=2, tiles="cartodbpositron")
    var_dummy=nome_variabile+"_dummy"
    style= lambda x :{'color': 'black','weight':0.5,'fillOpacity':0.2,'fillColor':colore_si if \
      x['properties'][var_dummy]==0 \
            else colore_no if x['properties'][var_dummy]==1 else 'grey'}
    testo=folium.features.GeoJsonTooltip(fields=["Country/Region",nome_variabile,"confirmed_cases","deaths_cases"],aliases=["Country",nome_variabile,"confirmed_cases","deaths_cases"])
    folium.GeoJson(worldjson, name=nome_variabile,style_function=style,tooltip=testo).add_to(m)
    
    #m.get_root().html.add_child(folium.Element(legend_html))
    m.get_root().add_child(macro)
    return m

Countries under LOCKDOWN

In [58]:
template = """
{% macro html(this, kwargs) %}

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>jQuery UI Draggable - Default functionality</title>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  
  <script>
  $( function() {
    $( "#maplegend" ).draggable({
                    start: function (event, ui) {
                        $(this).css({
                            right: "auto",
                            top: "auto",
                            bottom: "auto"
                        });
                    }
                });
});

  </script>
</head>
<body>

 
<div id='maplegend' class='maplegend' 
    style='position: absolute; z-index:9999; border:2px solid grey; background-color:rgba(255, 255, 255, 0.8);
     border-radius:6px; padding: 10px; font-size:14px; right: 20px; top: 20px;'>
     
<div class='legend-title'>Legend</div>
<div class='legend-scale'>
  <ul class='legend-labels'>
    <li><span style='background:green;opacity:0.2;'></span>Not Adopted</li>
    <li><span style='background:red;opacity:0.2;'></span>Lockdown</li>
    <li><span style='background:grey;opacity:0.2;'></span>Not Available</li>

  </ul>
</div>
</div>
 
</body>
</html>

<style type='text/css'>
  .maplegend .legend-title {
    text-align: left;
    margin-bottom: 5px;
    font-weight: bold;
    font-size: 90%;
    }
  .maplegend .legend-scale ul {
    margin: 0;
    margin-bottom: 5px;
    padding: 0;
    float: left;
    list-style: none;
    }
  .maplegend .legend-scale ul li {
    font-size: 80%;
    list-style: none;
    margin-left: 0;
    line-height: 18px;
    margin-bottom: 2px;
    }
  .maplegend ul.legend-labels li span {
    display: block;
    float: left;
    height: 16px;
    width: 30px;
    margin-right: 5px;
    margin-left: 0;
    border: 1px solid #999;
    }
  .maplegend .legend-source {
    font-size: 80%;
    color: #777;
    clear: both;
    }
  .maplegend a {
    color: #777;
    }
</style>
{% endmacro %}"""

macro = MacroElement()
macro._template = Template(template)
In [59]:
map_plotter("LOCKDOWN",colore_no='red')
Out[59]:

Countries that have closed school

In [12]:
template = """
{% macro html(this, kwargs) %}

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>jQuery UI Draggable - Default functionality</title>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  
  <script>
  $( function() {
    $( "#maplegend" ).draggable({
                    start: function (event, ui) {
                        $(this).css({
                            right: "auto",
                            top: "auto",
                            bottom: "auto"
                        });
                    }
                });
});

  </script>
</head>
<body>

 
<div id='maplegend' class='maplegend' 
    style='position: absolute; z-index:9999; border:2px solid grey; background-color:rgba(255, 255, 255, 0.8);
     border-radius:6px; padding: 10px; font-size:14px; right: 20px; top: 20px;'>
     
<div class='legend-title'>Legend</div>
<div class='legend-scale'>
  <ul class='legend-labels'>
    <li><span style='background:green;opacity:0.2;'></span>Schools open</li>
    <li><span style='background:violet;opacity:0.2;'></span>Schools closed</li>
    <li><span style='background:grey;opacity:0.2;'></span>Not Available</li>

  </ul>
</div>
</div>
 
</body>
</html>

<style type='text/css'>
  .maplegend .legend-title {
    text-align: left;
    margin-bottom: 5px;
    font-weight: bold;
    font-size: 90%;
    }
  .maplegend .legend-scale ul {
    margin: 0;
    margin-bottom: 5px;
    padding: 0;
    float: left;
    list-style: none;
    }
  .maplegend .legend-scale ul li {
    font-size: 80%;
    list-style: none;
    margin-left: 0;
    line-height: 18px;
    margin-bottom: 2px;
    }
  .maplegend ul.legend-labels li span {
    display: block;
    float: left;
    height: 16px;
    width: 30px;
    margin-right: 5px;
    margin-left: 0;
    border: 1px solid #999;
    }
  .maplegend .legend-source {
    font-size: 80%;
    color: #777;
    clear: both;
    }
  .maplegend a {
    color: #777;
    }
</style>
{% endmacro %}"""

macro = MacroElement()
macro._template = Template(template)
In [13]:
map_plotter("SCHOOL_CLOSING")
Out[13]:

Countries that have adopted digital tracking system

In [14]:
template = """
{% macro html(this, kwargs) %}

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>jQuery UI Draggable - Default functionality</title>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  
  <script>
  $( function() {
    $( "#maplegend" ).draggable({
                    start: function (event, ui) {
                        $(this).css({
                            right: "auto",
                            top: "auto",
                            bottom: "auto"
                        });
                    }
                });
});

  </script>
</head>
<body>

 
<div id='maplegend' class='maplegend' 
    style='position: absolute; z-index:9999; border:2px solid grey; background-color:rgba(255, 255, 255, 0.8);
     border-radius:6px; padding: 10px; font-size:14px; right: 20px; top: 20px;'>
     
<div class='legend-title'>Legend</div>
<div class='legend-scale'>
  <ul class='legend-labels'>
    <li><span style='background:yellow;opacity:0.2;'></span>digital tracking</li>
    <li><span style='background:green;opacity:0.2;'></span>NO Digital Tracking</li>
    <li><span style='background:grey;opacity:0.2;'></span>Not Available</li>

  </ul>
</div>
</div>
 
</body>
</html>

<style type='text/css'>
  .maplegend .legend-title {
    text-align: left;
    margin-bottom: 5px;
    font-weight: bold;
    font-size: 90%;
    }
  .maplegend .legend-scale ul {
    margin: 0;
    margin-bottom: 5px;
    padding: 0;
    float: left;
    list-style: none;
    }
  .maplegend .legend-scale ul li {
    font-size: 80%;
    list-style: none;
    margin-left: 0;
    line-height: 18px;
    margin-bottom: 2px;
    }
  .maplegend ul.legend-labels li span {
    display: block;
    float: left;
    height: 16px;
    width: 30px;
    margin-right: 5px;
    margin-left: 0;
    border: 1px solid #999;
    }
  .maplegend .legend-source {
    font-size: 80%;
    color: #777;
    clear: both;
    }
  .maplegend a {
    color: #777;
    }
</style>
{% endmacro %}"""

macro = MacroElement()
macro._template = Template(template)
In [15]:
map_plotter("TRACKING",colore_no='yellow')
Out[15]:

Countries that have suspended elections

In [16]:
template = """
{% macro html(this, kwargs) %}

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>jQuery UI Draggable - Default functionality</title>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  
  <script>
  $( function() {
    $( "#maplegend" ).draggable({
                    start: function (event, ui) {
                        $(this).css({
                            right: "auto",
                            top: "auto",
                            bottom: "auto"
                        });
                    }
                });
});

  </script>
</head>
<body>

 
<div id='maplegend' class='maplegend' 
    style='position: absolute; z-index:9999; border:2px solid grey; background-color:rgba(255, 255, 255, 0.8);
     border-radius:6px; padding: 10px; font-size:14px; right: 20px; top: 20px;'>
     
<div class='legend-title'>Legend</div>
<div class='legend-scale'>
  <ul class='legend-labels'>
    <li><span style='background:steelblue;opacity:0.2;'></span>suspended elections</li>
    <li><span style='background:green;opacity:0.2;'></span>not suspended</li>
    <li><span style='background:grey;opacity:0.2;'></span>Not Available</li>

  </ul>
</div>
</div>
 
</body>
</html>

<style type='text/css'>
  .maplegend .legend-title {
    text-align: left;
    margin-bottom: 5px;
    font-weight: bold;
    font-size: 90%;
    }
  .maplegend .legend-scale ul {
    margin: 0;
    margin-bottom: 5px;
    padding: 0;
    float: left;
    list-style: none;
    }
  .maplegend .legend-scale ul li {
    font-size: 80%;
    list-style: none;
    margin-left: 0;
    line-height: 18px;
    margin-bottom: 2px;
    }
  .maplegend ul.legend-labels li span {
    display: block;
    float: left;
    height: 16px;
    width: 30px;
    margin-right: 5px;
    margin-left: 0;
    border: 1px solid #999;
    }
  .maplegend .legend-source {
    font-size: 80%;
    color: #777;
    clear: both;
    }
  .maplegend a {
    color: #777;
    }
</style>
{% endmacro %}"""

macro = MacroElement()
macro._template = Template(template)
In [17]:
map_plotter("ELECTIONS_SUSPENSION",colore_no="steelblue")
Out[17]:

by clicking on the link below you can see the raw code used to produce the graphs

In [18]:
from IPython.display import HTML

HTML('''<script>
code_show=true; 
function code_toggle() {
 if (code_show){
 $('div.input').hide();
 } else {
 $('div.input').show();
 }
 code_show = !code_show
} 
$( document ).ready(code_toggle);
</script>
<form action="javascript:code_toggle()"><input type="submit" value="Click here to toggle on/off the raw code."></form>''')
Out[18]: